package com.freeleaps.devops

/**
 * 语义化发布执行器类
 * 负责执行基于语义化版本控制的自动化发布流程
 * 使用semantic-release工具根据提交信息自动生成版本号、发布说明和Git标签
 * 支持多种发布插件：Git操作、变更日志生成、执行自定义脚本等
 * 提供统一的发布管理接口，确保版本发布的一致性和自动化
 */
class SemanticReleasingExecutor {
  // Jenkins Pipeline的steps对象，用于调用Jenkins内置功能
  def steps
  // 工作空间路径，发布操作的目标目录
  def workspace
  // 语义化发布配置文件路径
  def config
  // 语义化发布所需的插件列表
  // 这些插件用于处理不同的发布任务：版本管理、Git操作、变更日志等
  def plugins = [
    'semantic-release',                                    // 核心语义化发布工具
    '@semantic-release/git',                               // Git操作插件：创建标签、推送等
    '@semantic-release/changelog',                         // 变更日志生成插件
    '@semantic-release/exec',                              // 执行自定义脚本插件
    'conventional-changelog-conventionalcommits'           // 约定式提交变更日志插件
  ]

  /**
   * 构造函数
   * @param steps Jenkins Pipeline的steps对象
   * @param workspace 工作空间路径
   */
  SemanticReleasingExecutor(steps, workspace) {
    this.steps = steps
    this.workspace = workspace
    // TODO: 配置文件路径应该作为参数传入，而不是硬编码
    // 当前使用Shared Library中的默认配置文件
    this.config = 'com/freeleaps/devops/builtins/semantic-release/releaserc.json'
  }

  /**
   * 执行语义化发布的主要方法
   * 根据提交信息自动生成版本号、创建Git标签、生成变更日志
   * 支持Git认证和分支管理，确保发布流程的自动化
   * 
   * @param credentialsId Jenkins中存储的Git认证凭据ID
   * @param branch 发布分支名称
   */
  def release(credentialsId, branch) {
    // 记录配置信息
    steps.log.warn("SemanticReleasingExecutor", "Configuration file customization is not supported yet, using builtin release rules as fallback")
    steps.log.info("SemanticReleasingExecutor", "Releasing with config: ${config}")

    // 切换到工作根目录
    steps.dir(steps.env.workroot) {
      // 需要插件：Credentials Plugin - 提供withCredentials功能，用于安全地使用认证凭据
      steps.withCredentials([steps.usernamePassword(credentialsId: credentialsId, passwordVariable: 'GIT_PASSWORD', usernameVariable: 'GIT_USERNAME')]) {
        // 设置Git认证信息
        steps.env.GIT_CREDENTIALS = "${steps.env.GIT_USERNAME}:${steps.env.GIT_PASSWORD}"
        
        // 需要插件：Pipeline Plugin (基础插件) - 提供writeFile和libraryResource功能
        // 从Shared Library资源中读取配置文件并写入工作空间
        steps.writeFile file: '.releaserc.json', text: steps.libraryResource(config)
        
        // 配置Git安全目录，避免Git安全警告
        steps.sh "git config --global --add safe.directory ${steps.env.workroot}"
        
        // 设置本地分支环境变量
        steps.env.GIT_LOCAL_BRANCH = "${branch}"

        // 记录发布前的版本号，用于判断是否有新版本发布
        def previousVersion = ""
        def versionFileExistsBefore = steps.sh(script: 'test -f "VERSION"', returnStatus: true) == 0
        if (versionFileExistsBefore) {
          // 需要插件：Pipeline Plugin (基础插件) - 提供readFile功能
          previousVersion = steps.readFile('VERSION').trim()
          steps.log.info("SemanticReleasingExecutor", "Previous version: ${previousVersion}")
        }

        // 执行语义化发布
        // 需要插件：Pipeline Plugin (基础插件) - 提供sh功能，用于执行Shell命令
        // semantic-release工具会根据提交信息自动：
        // 1. 分析提交信息，确定版本类型（major/minor/patch）
        // 2. 生成新的版本号
        // 3. 创建Git标签
        // 4. 生成变更日志
        // 5. 更新VERSION文件
        steps.sh """
          #!/bin/bash
          semantic-release
        """
        steps.log.info("SemanticReleasingExecutor", "Semantic release completed, read latest version from VERSION file")

        // 检查VERSION文件是否存在，判断发布是否成功
        def versionFileExists = steps.sh(script: 'test -f "VERSION"', returnStatus: true) == 0
        def released = false

        if (versionFileExists) {
          // 读取当前版本号
          def currentVersion = steps.readFile('VERSION').trim()
          // 判断是否有新版本发布：
          // 1. 如果之前没有VERSION文件，说明是首次发布
          // 2. 如果当前版本与之前版本不同，说明有新版本发布
          released = !versionFileExistsBefore || (currentVersion != previousVersion)
          
          if (released) {
            // 设置环境变量，供后续步骤使用
            steps.env.LATEST_VERSION = steps.readFile('VERSION').trim()
            steps.env.SEMANTIC_RELEASED = true
            steps.log.info("SemanticReleasingExecutor", "Semantic release completed, version: ${steps.env.LATEST_VERSION}")
          } else {
            steps.log.warn("SemanticReleasingExecutor", "No new version released, current version remains: ${currentVersion}")
          }
        } else {
          steps.log.warn("SemanticReleasingExecutor", "VERSION file not found, semantic release may have failed ?")
        }
      }
    }
  }
}